package com.happy3w.bean.factory;

import com.happy3w.toolkits.message.MessageRecorderException;
import lombok.AllArgsConstructor;
import lombok.Getter;

import java.lang.reflect.Constructor;
import java.text.MessageFormat;
import java.util.HashMap;
import java.util.Map;

@Getter
@AllArgsConstructor
public class BeanConstructorConfig<C, B> {
    private Class<C> configType;
    private Class<B> beanType;
    private Constructor<B> beanConstructor;

    public static  <C, B> void initBeanTypes(
            Class<C> configType,
            Class<B> beanType,
            Map<Class, BeanConstructorConfig> beanConstructorConfigs,
            TypeDetector typeDetector,
            String... packageNames) {
        for (String packageName : packageNames) {
            typeDetector.detect(packageName, beanType).forEach(pair -> {
                Class<? extends B> bType = pair.getValue();
                Constructor<?>[] constructors = bType.getConstructors();
                for (Constructor<?> constructor : constructors) {
                    Class<?>[] pTypes = constructor.getParameterTypes();
                    for (Class pType : pTypes) {
                        if (configType.isAssignableFrom(pType)) {
                            BeanConstructorConfig<C, B> existConfig = beanConstructorConfigs.get(pType);
                            if (existConfig != null) {
                                throw new MessageRecorderException(MessageFormat.format(
                                        "Config {0} has multiple bean type:{1}, {2}.",
                                        pType, bType, existConfig.getBeanType()));
                            }
                            beanConstructorConfigs.put(pType, new BeanConstructorConfig(pType, bType, constructor));
                        }
                    }
                }
            });
        }
    }

    public static <T, S> Map<Class<? extends T>, BeanConstructorConfig<T, S>> initBeanTypes(
            Class<T> configType, Class<S> beanType,
            TypeDetector typeDetector,
            String... packageNames) {
        Map beanConstructorConfigs = new HashMap<>();
        initBeanTypes(configType, beanType, beanConstructorConfigs, typeDetector, packageNames);
        return (Map<Class<? extends T>, BeanConstructorConfig<T, S>>) beanConstructorConfigs;
    }
}
